﻿using Net.ColorMath;
using NetBase;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Net.NetBase
{
    public class Area
    {

        public SqImgLayer Layer { get; set; }

        public SqRt InitialElement { get; set; }

        private List<SqRt> elements = new List<SqRt>();

        public List<SqRt> Elements { 
            get
            {
                return elements;
            }
        }

        public void AddElement( SqRt el )
        {
            if (!el.nels.Any((v) => v.Value.Area == this))
            {
                throw new Exception("Can't add element without Area border");
            }
            el.Area = this;
            el.IsAreaBorder = true;
            elements.Add(el);
            foreach (var kel in el.nels.Where((v) => v.Value.Area == this))
            {
                kel.Value.IsAreaBorder = kel.Value.nels.Any((v) => v.Value.Area != this);
            }
            el.IsAreaBorder = el.nels.Any((v) => v.Value.Area != this);
        }

        public void RemoveElement(SqRt el)
        {
            if (!el.nels.Any((v) => v.Value.Area != this))
            {
                throw new Exception("Can't remove element without Area border");
            }
            el.Area = null;
            el.IsAreaBorder = false;
            elements.Remove(el);
            foreach (var kel in el.nels.Where((v) => v.Value.Area == this))
            {
                kel.Value.IsAreaBorder = true;
            }
        }

        public Area()
        {
            
        }

        public Area(params SqRt[] el)
        {
            bool isFirst = true;
            foreach (var el1 in el)
            {
                if (isFirst)
                {
                    isFirst = false;
                    InitialElement = el1;
                }
                el1.Area = this;
                el1.IsAreaBorder = true;
                elements.Add(el1);
            }
        }

        internal void AddMinNCGElement()
        {
            //Console.Out.WriteLine("************");
            List<Tuple<SqRt, SqRt, float>> minItems = new List<Tuple<SqRt, SqRt, float>>();
            foreach ( var el in elements.Where(item => item.IsAreaBorder) )
            {
                if ((el.nels.Where(item => (item.Value.Area == null))).Count() > 0)
                {
                    foreach (var minEl in el.nels.Where(item => (item.Value.Area == null))) //.ArgMin((it) => CW.GetModule(el.Input - it.Value.Input));
                    {
                        var nearestByColor = minEl.Value.nels.ArgMin(elem => CW.GetModule(elem.Value.Input - minEl.Value.Input)).Value;
                        if (nearestByColor == el)
                        {
                            minItems.Add(new Tuple<SqRt, SqRt, float>(el, minEl.Value, CW.GetModule(el.Input - minEl.Value.Input)));
                            //Console.Out.WriteLine("Add item");
                        }
                    }
                }
                //Console.Out.Write(String.Format("El({0},{1}) ", el.X, el.Y));
            }
            if (minItems.Count() > 0)
            {
                var mostMinItem = minItems.ArgMin((item) => item.Item3);
                //var minElementToAdd = mostMinItem.Item2;
                //var nearestByColor = minElementToAdd.nels.ArgMin(el => CW.GetModule(el.Value.Input - minElementToAdd.Input)).Value;
                //if (nearestByColor == mostMinItem.Item1)
                {
                    AddElement(mostMinItem.Item2);
                    Console.Out.WriteLine("Add item");
                }
            }
            //Console.Out.WriteLine("");
            //Console.Out.Write(String.Format("ADD({0},{1}) ", mostMinItem.Item2.X, mostMinItem.Item2.Y));
            //Console.Out.WriteLine("======================");
        }

        internal void AddNCGElement()
        {
            List<Tuple<SqRt, SqRt, float>> minItems = new List<Tuple<SqRt, SqRt, float>>();
            foreach (var el in elements.Where(item => item.IsAreaBorder))
            {
                if ((el.nels.Where(item => (item.Value.Area == null))).Count() > 0)
                {
                    var minEl = el.nels.Where(item => (item.Value.Area == null)).ArgMin((it) => CW.GetModule(el.Input - it.Value.Input));
                    //var nearestByColor = minEl.Value.nels.ArgMin(elem => CW.GetModule(elem.Value.Input - minEl.Value.Input)).Value;
                    //if (nearestByColor == el)
                    {
                        minItems.Add(new Tuple<SqRt, SqRt, float>(el, minEl.Value, CW.GetModule(el.Input - minEl.Value.Input)));
                        Console.Out.WriteLine("Add item");
                    }
                }
            }
            if (minItems.Count() > 0)
            {
                var mostMinItem = minItems.ArgMin((item) => item.Item3);
                AddElement(mostMinItem.Item2);
            }
        }

        public IEnumerable<Tuple<SqRt, SqRt, float>> AddMinNCGElementThem()
        {
            //Console.Out.WriteLine("************");
            //List<Tuple<SqRt, SqRt, float>> minItems = new List<Tuple<SqRt, SqRt, float>>();
            foreach (var el in elements.Where(item => item.IsAreaBorder))
            {
                if ((el.nels.Where(item => (item.Value.Area == null))).Count() > 0)
                {
                    var minEl = el.nels.Where(item => (item.Value.Area == null)).ArgMin((it) => CW.GetModule(el.Input - it.Value.Input));
                    {
                        //var nearestByColor = minEl.Value.nels.ArgMin(elem => CW.GetModule(elem.Value.Input - minEl.Value.Input)).Value;
                        //if (nearestByColor == el)
                        {
                            yield return new Tuple<SqRt, SqRt, float>(el, minEl.Value, CW.GetModule(el.Input - minEl.Value.Input));
                            //Console.Out.WriteLine("Add item");
                        }
                    }
                }
                //Console.Out.Write(String.Format("El({0},{1}) ", el.X, el.Y));
            }
            //if (minItems.Count() > 0)
            //{
            //    var mostMinItem = minItems.ArgMin((item) => item.Item3);
            //    //var minElementToAdd = mostMinItem.Item2;
            //    //var nearestByColor = minElementToAdd.nels.ArgMin(el => CW.GetModule(el.Value.Input - minElementToAdd.Input)).Value;
            //    //if (nearestByColor == mostMinItem.Item1)
            //    {
            //        AddElement(mostMinItem.Item2);
            //        Console.Out.WriteLine("Add item");
            //    }
            //}            
        }
    }
}
